package com.tarena.demo.luban.all.main.consumer;

import com.tarena.demo.luban.all.main.service.OrderService;
import com.tarena.demo.luban.commons.exception.BusinessDemoException;
import com.tarena.demo.luban.commons.restful.ResponseCode;
import com.tarena.demo.luban.protocol.order.param.OrderAddParam;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Component
@RocketMQMessageListener(topic = "order-add-topic",consumerGroup = "${rocketmq.consumer.group}")
public class OrderAddConsumer implements RocketMQListener<OrderAddParam> {
    @Autowired
    private OrderService orderService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public void onMessage(OrderAddParam message) {
        // 抢锁的所有参数都准备好 lockkey 同一个订单orderSn 锁相同的randCode
        String lockKey = "order:add:"+message.getOrderSn()+"lock";
        String randCode = new Random().nextInt(9000)+1000+"";
        // 使用string操作对象 调用setnx命令
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        // 抢锁setnx ｛lockkey｝
        Boolean tryLock = opsForValue.setIfAbsent(lockKey,randCode,10, TimeUnit.SECONDS);
        try{
            while(!tryLock){
                //只要tryLock是false 就是没抢到 等待5秒继续抢
                //TODO 可以在while中添加一些代码逻辑细节,比如: 最多允许一个线程抢三次
                //TODO 每次抢都比之前少等一会,让等待次数多的人更可能抢到锁
                Thread.sleep(5000);
                tryLock = opsForValue.setIfAbsent(lockKey,randCode,10,TimeUnit.SECONDS);
            }
            //抢到锁 执行业务逻辑
            orderService.addOrder(message);
        }catch (BusinessDemoException e){
            //记录打印日志 结束
        }catch (Throwable e){
            //连接数据库 dubbo调用等问题
            throw new BusinessDemoException(ResponseCode.BAD_REQUEST,"系统异常");
        }finally {
            //先读取 锁的value
            String getValue=opsForValue.get(lockKey);
            if (getValue==randCode){
                redisTemplate.delete(lockKey);
            }
        }
    }
}
